package com.golxen.framework.common.server.game.sync.message;


import com.golxen.framework.GameErrorCode;
import com.golxen.protojava.SyncMessage;

import java.time.Duration;
import java.time.LocalDateTime;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;

public class SyncMessageDispatcher {

	private final AtomicLong sequenceId = new AtomicLong();
    private final Map<Long, SyncResultProcessor> pendingMap = new ConcurrentHashMap<>();

    public SyncMessageDispatcher() {

    }

    public SyncResultProcessor pending(SyncMessage.Request.Builder request) {
        long l = sequenceId.incrementAndGet();
        request.setSequenceId(l);
        SyncResultProcessor resultProcessor = new SyncResultProcessor(l);
        pendingMap.put(resultProcessor.getSequenceId(), resultProcessor);
        return resultProcessor;
    }


    public void receive(SyncMessage.Response response) {
        SyncResultProcessor resultProcessor = pendingMap.remove(response.getSequenceId());
        if (resultProcessor != null) {
            if (resultProcessor.getResponseBuilder() != null) {
                try {
                    resultProcessor.getResponseBuilder().mergeFrom(response.getDataBytes()).buildPartial();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            SyncResponse syncResponse = new SyncResponse();
            syncResponse.setResponseBuilder(resultProcessor.getResponseBuilder());
            syncResponse.setErrorCode(response.getErrorCode());
            resultProcessor.getCompletableFuture().complete(syncResponse);
        }
    }


    public void scheduleCleanResultProcessor() {
        SyncResponse syncResponse = new SyncResponse();
        syncResponse.setErrorCode(GameErrorCode.E_ERROR_TIME_OUT);
        LocalDateTime now = LocalDateTime.now();
        this.pendingMap.forEach((k, v) -> {
            long seconds = Duration.between(v.getCreateAt(), now).getSeconds();
            if (seconds < 5) {
                return;
            }
            SyncResultProcessor resultProcessor = this.pendingMap.remove(v.getSequenceId());
            if (resultProcessor != null) {
                resultProcessor.getCompletableFuture().complete(syncResponse);
            }
        });
    }

}
